package user

import (
	"context"
	"errors"
	"git.mycaigou.com/gfyx/micro-gfyx-api/infrastructure/dto/base"
	"git.mycaigou.com/gfyx/micro-gfyx-api/infrastructure/repository/base/user"
	"git.mycaigou.com/gfyx/micro-gfyx-api/infrastructure/utils/auth"
	microGfyxOpptyService "git.mycaigou.com/gfyx/micro-gfyx-api/proto/micro_gfyx_oppty_service_proto/micro-gfyx-oppty-service/base"
	"git.myscrm.cn/golang/stark/v4"
)

type LoginService struct {
	loginRepo user.LoginRepositoryIface
}

// NewLoginService 构造函数
func NewLoginService(loginRepo user.LoginRepositoryIface) LoginServiceIface {
	return &LoginService{
		loginRepo: loginRepo,
	}
}

func (s *LoginService) UnionUserLogin(ctx context.Context, tenantCode, account, password string) (*user.UnionUserLoginInfo, error) {
	loginInfo, err := s.loginRepo.UnionUserLogin(ctx, tenantCode, account, password)
	if err != nil {
		return nil, err
	}

	if loginInfo == nil {
		return nil, errors.New("登录失败")
	}

	//loginInfo.Token, err = s.jwkToken(loginInfo)
	//if err != nil {
	//	return nil, err
	//}

	return loginInfo, nil
}

// LoginByPassword 账号密码登录
func (s *LoginService) LoginByPassword(ctx context.Context, request base.UsingPasswordRequest) (*base.UsingPasswordResponse, error) {
	pbRequest := &microGfyxOpptyService.LoginByPasswordRequest{
		TenantCode:    request.TenantCode,
		Account:       request.Account,
		Password:      request.Password,
		CaptchaId:     request.CaptchaID,
		CaptchaAnswer: request.CaptchaAnswer,
		Remember:      request.Remember,
	}
	pbResponse, err := s.loginRepo.LoginByPassword(ctx, pbRequest)
	if err != nil {
		stark.Logger.Error(ctx, "call login grpc failed:"+err.Error())
		return nil, err
	}
	response := &base.UsingPasswordResponse{
		AccessToken:  pbResponse.AccessToken,
		RefreshToken: pbResponse.RefreshToken,
		ExpireTime:   pbResponse.ExpireTime,
	}

	return response, nil
}

// LoginByPhone 验证码登录
func (s *LoginService) LoginByPhone(ctx context.Context, request base.UsingPhoneRequest) (*base.UsingPhoneResponse, error) {
	pbRequest := &microGfyxOpptyService.LoginByPhoneRequest{
		TenantCode: request.TenantCode,
		Mobile:     request.Mobile,
		Code:       request.Code,
		Remember:   request.Remember,
	}
	pbResponse, err := s.loginRepo.LoginByPhone(ctx, pbRequest)
	if err != nil {
		stark.Logger.Error(ctx, "call login grpc failed:"+err.Error())
		return nil, err
	}
	response := &base.UsingPhoneResponse{
		AccessToken:  pbResponse.AccessToken,
		RefreshToken: pbResponse.RefreshToken,
		ExpireTime:   pbResponse.ExpireTime,
	}

	return response, nil
}

// GetResetPasswordToken 获取临时 token
func (s *LoginService) GetResetPasswordToken(ctx context.Context, request base.GetResetPasswordTokenRequest) (*base.GetResetPasswordTokenResponse, error) {
	pbRequest := &microGfyxOpptyService.GetResetPasswordTokenRequest{
		TenantCode: request.TenantCode,
		Mobile:     request.Mobile,
		Code:       request.Code,
	}
	resp, err := s.loginRepo.GetResetPasswordToken(ctx, pbRequest)
	if err != nil {
		stark.Logger.Errorf(ctx, "call reset password token grpc failed:%v", err)
		return nil, err
	}

	return &base.GetResetPasswordTokenResponse{
		Token: resp.Token,
	}, nil
}

// ResetPasswordByPhone 重设密码
func (s *LoginService) ResetPasswordByPhone(ctx context.Context, request base.ResetByPhoneRequest) (*base.ResetByPhoneResponse, error) {
	pbRequest := &microGfyxOpptyService.ResetPasswordByPhoneRequest{
		TenantCode: request.TenantCode,
		Mobile:     request.Mobile,
		Password:   request.Password,
		Token:      request.Token,
	}
	_, err := s.loginRepo.ResetPasswordByPhone(ctx, pbRequest)
	if err != nil {
		stark.Logger.Errorf(ctx, "call reset password grpc failed:%v", err)
		return nil, err
	}

	return new(base.ResetByPhoneResponse), err
}

// Sso 单点登录
func (s *LoginService) Sso(ctx context.Context, params *microGfyxOpptyService.SsoRequest) (*base.SsoResponse, error) {
	ssoResponse, err := s.loginRepo.Sso(ctx, params)
	if err != nil {
		stark.Logger.Errorf(ctx, "login-sso failed:%v", err)
		return nil, err
	}

	return &base.SsoResponse{
		AccessToken:  ssoResponse.AccessToken,
		RefreshToken: ssoResponse.RefreshToken,
		ExpireTime:   ssoResponse.ExpireTime,
		Url:          ssoResponse.Url,
	}, nil
}

// LoginUser 获取登录用户信息
func (s *LoginService) LoginUser(ctx context.Context, token string) (*auth.LoginUserInfo, error) {
	params := &microGfyxOpptyService.LoginUserRequest{
		Token: token,
	}

	loginUser, err := s.loginRepo.LoginUserInfo(ctx, params)
	if err != nil {
		// stark.Logger.Errorf(ctx, "grpc LoginUserInfo failed:%v", err)
		return nil, err
	}

	return &auth.LoginUserInfo{
		User: auth.UserInfoItem{
			UserId:        loginUser.Id,
			UserGuid:      loginUser.Uid,
			Account:       loginUser.Account,
			Name:          loginUser.Name,
			Mobile:        loginUser.Mobile,
			Email:         loginUser.Email,
			Position:      loginUser.Position,
			ResetPassword: int(loginUser.ResetPassword),
		},
		Tenant: auth.TenantInfo{
			TenantName: loginUser.TenantName,
			TenantCode: loginUser.TenantCode,
			Profits:    loginUser.Profits,
		},
	}, nil
}

func (s *LoginService) LogoutUser(ctx context.Context, token string) (bool, error) {
	params := &microGfyxOpptyService.LogoutRequest{
		Token: token,
	}
	_, err := s.loginRepo.LogoutUser(ctx, params)
	if err != nil {
		stark.Logger.Errorf(ctx, "grpc LogoutUser failed:%v", err)
		return false, err
	}

	return true, nil
}

func (s *LoginService) RefreshToken(ctx context.Context, request base.RefreshTokenRequest) (*base.RefreshTokenResponse, error) {
	params := &microGfyxOpptyService.RefreshTokenRequest{
		TenantCode:   request.TenantCode,
		RefreshToken: request.RefreshToken,
	}
	resp, err := s.loginRepo.RefreshToken(ctx, params)
	if err != nil {
		// 在下游记录
		return nil, err
	}

	return &base.RefreshTokenResponse{
		AccessToken:  resp.Token,
		RefreshToken: resp.RefreshToken,
		ExpireTime:   resp.ExpireTime,
	}, nil
}

func (s *LoginService) ClearUserLockCache(ctx context.Context, request base.ReleaseAccountRequest) error {
	isSuccess := auth.NewAuth().ReleaseLocked(ctx, request.Account)
	if !isSuccess {
		return errors.New("clear user lock cache failed")
	}
	return nil
}
